package smallfrench.moteur.interp;

import java.util.HashMap;

import smallfrench.moteur.biblio.err.ErreurVariableIndefinie;
import smallfrench.moteur.interp.err.RException;

/**
 * Classe pour la gestion d’une portée statique.
 * @author antoine1013
 */
public class Portee {

	/**
	 * La map interne des entrées nom - valeur
	 */
	private final HashMap<String, RObjet> map;

	/**
	 * La portée parente
	 */
	private final Portee parent;

	/**
	 * L’objet courant ou <code>null</code> si la portée n’est pas dans une
	 * classe.
	 */
	public final RObjet moi;

	//-----------------------------------------------------------------

	public Portee() {
		parent = null;
		map = new HashMap<String, RObjet>();
		moi = null;
	}

	public Portee(Portee parent) {
		this.parent = parent;
		map = new HashMap<String, RObjet>();
		moi = parent.moi;
	}

	public Portee(Portee parent, RObjet moi) {
		this.parent = parent;
		map = new HashMap<String, RObjet>();
		this.moi = moi;
	}

	//-----------------------------------------------------------------

	/**
	 * Recherche une variable dans cette portée, puis dans chaque portée
	 * parente.
	 * @param nom
	 * @return La valeur de la variable
	 * @throws RException Si la variable n’existe pas
	 */
	public RObjet getVariable(String nom) throws RException {

		if (map.containsKey(nom)) {
			return map.get(nom);
		} else {
			if (parent != null) {
				return parent.getVariable(nom);
			} else {
				throw ErreurVariableIndefinie.nouvelleException(nom);
			}
		}
	}

	//	/**
	//	 *
	//	 * @return L’objet courant
	//	 * @throws RException Si la portée n’est pas dans une classe.
	//	 */
	//	public RObjet getMoi() throws RException {
	//		if (moi != null)
	//			return moi;
	//		else {
	//			if (parent != null)
	//				return parent.getMoi();
	//			else
	//				throw ErreurVariableIndefinie.nouvelleException("moi");
	//		}
	//	}

	/**
	 * 
	 * @return L’objet courant
	 * @throws RException Si la portée n’est pas dans une classe.
	 */
	public RObjet getMoi() throws RException {
		if (moi != null) {
			return moi;
		} else {
			throw ErreurVariableIndefinie.nouvelleException("moi");
		}
	}

	/**
	 * Modifie une variable si elle existe
	 * @param nom
	 * @param valeur
	 * @throws RException Au cas où la variable n’existe pas.
	 */
	public void setVariable(String nom, RObjet valeur)
			throws RException {

		if (map.containsKey(nom)) {
			map.put(nom, valeur);
		} else {
			if (parent != null) {
				parent.setVariable(nom, valeur);
			} else {
				throw ErreurVariableIndefinie.nouvelleException(nom);
			}
		}
	}

	/**
	 * Ajoute ou remplace la variable nom.
	 * @param nom
	 * @param valeur
	 */
	public void ajouterVariable(String nom, RObjet valeur) {
		map.put(nom, valeur);
	}

	/**
	 * Ajoute toutes les variables
	 * @param map
	 */
	public void ajouterVariables(HashMap<String, RObjet> map) {
		this.map.putAll(map);
	}
}
